using System;
using System.Collections.Generic;
using System.Text;

namespace UserInterface.MML.Base
{
    public interface IItem
    {
    }

    public abstract class ItemContainer
    {
        private List<IItem> items =
            new List<IItem>();

        public List<IItem> Items
        {
            get { return items; }
        }
    }

    public class ParseTree : ItemContainer
    {
    }

    public class CharacterDataItem : IItem
    {
        private string data;

        public CharacterDataItem(string data)
        {
            this.data = data;
        }

        public string Data
        {
            get { return data; }
            set { data = value; }
        }
    }

    public class TagItem : ItemContainer, IItem
    {
        private string name;
        private string value;
        private string startTagCode;
        private string endTagCode;
        private Dictionary<string, TagItemAttribute> attributes =
            new Dictionary<string, TagItemAttribute>();

        public TagItem(
            string name,
            string value,
            string startTagCode,
            string endTagCode
        )
        {
            this.name = name;
            this.value = value;
            this.startTagCode = startTagCode;
            this.endTagCode = endTagCode;
        }

        public string Name
        {
            get { return name; }
        }

        public string Value
        {
            get { return value; }
        }

        public string StartTagCode
        {
            get { return startTagCode; }
        }

        public string EndTagCode
        {
            get { return endTagCode; }
        }

        public bool IsSelfClosing
        {
            get { return endTagCode == null; }
        }

        public Dictionary<string, TagItemAttribute> Attributes
        {
            get { return attributes; }
        }

        public void AddAttribute(string name, string value, string code)
        {
            attributes[name] = new TagItemAttribute(name, value, code);
        }
    }

    public class TagItemAttribute
    {
        private string name;
        private string value;
        private string code;

        public TagItemAttribute(
            string name,
            string value,
            string code
        )
        {
            this.name = name;
            this.value = value;
            this.code = code;
        }

        public string Name
        {
            get { return name; }
        }

        public string Value
        {
            get { return value; }
        }

        public string Code
        {
            get { return code; }
        }
    }

    internal class CandidateTag : IItem
    {
        private string name;
        private string value;
        private List<Token> tokens = new List<Token>();
        private Dictionary<string, CandidateTagAttribute> attributes =
            new Dictionary<string, CandidateTagAttribute>();

        public CandidateTag(string name)
        {
            this.name = name;
        }

        public string Name
        {
            get { return name; }
        }

        public string Value
        {
            get { return value; }
            set { this.value = value; }
        }

        public List<Token> Tokens
        {
            get { return tokens; }
        }

        public Dictionary<string, CandidateTagAttribute> Attributes
        {
            get { return attributes; }
        }

        public void AddAttribute(string name, string value, string code)
        {
            attributes[name] = new CandidateTagAttribute(name, value, code);
        }

        public string GetOriginalCode()
        {
            StringBuilder code = new StringBuilder();
            foreach (Token token in Tokens)
            {
                code.Append(token.Code);
            }
            return code.ToString();
        }
    }

    internal class CandidateTagAttribute
    {
        private string name;
        private string value;
        private string code;

        public CandidateTagAttribute(
            string name,
            string value,
            string code
        )
        {
            this.name = name;
            this.value = value;
            this.code = code;
        }

        public string Name
        {
            get { return name; }
        }

        public string Value
        {
            get { return value; }
        }

        public string Code
        {
            get { return code; }
        }
    }
}
